package com.beantools.reflect.clone;

import com.beantools.entity.EntityStorage;
import com.beantools.execption.ClassException;
import com.beantools.execption.InformationException;
import com.beantools.factory.reflect.CommonReflectFactory;
import com.beantools.filters.BuilderFilters;
import com.beantools.filters.MethodFilters;
import com.beantools.reflect.property.Property;
import com.beantools.util.ArrayUtil;
import com.beantools.util.CollectionUtil;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import static com.beantools.constants.SingleChar.EN_POINT;
import static com.beantools.constants.SingleChar.SIGN_COLON_OP;
import static com.beantools.util.CollectionUtil.containNullObj;
import static com.beantools.util.CollectionUtil.isEmpty;
import static com.beantools.util.ObjectUtil.isNull;
import static com.beantools.util.StringUtil.*;
import static com.beantools.util.poutil.MethodUtil.invoke;
import static java.math.BigDecimal.ROUND_DOWN;

/**
 * 这个是用来克隆对象的类。比如我们在进行C/S开发，当后台更新数据对象时，
 * 前端通过页面向后端传递某个对象，调用者拿到该对象后，再拿到数据库对象。
 * 我们把该对象填充到数据库对象中，再保存到数据库当中。比如以下代码：
 * <pre>
 *     <code>
 *          @Override
 *          public Result saveUpdateSupplier(Supplier supplier){
 *              Supplier dbSupplier=(Supplier)getSession().get(Supplier.class,supplier.getId());
 *              dbSupplier.setName(supplier.getName());
 *              dbSupplier.setBusinessType(supplier.getBusinessType());
 *              dbSupplier.setTel(supplier.getTel());
 *              dbSupplier.setFax(supplier.getFax());
 *              dbSupplier.setAddress(supplier.getAddress());
 *              return ResultUtil.buildSuccess(supplierDao.saveUpdateSupplier(dbSupplier));
 *          }
 *     </code>
 * </pre>
 *
 * @author baoya
 * @version 1.1.0
 * @since 1.0
 */
@SuppressWarnings("all")
public class Clone<T> implements Serializable, Cloneable {

    private static final long serialVersionUID = 8891025672140137776L;

    private static Clone instance = null;

    private Clone() {
    }

    public synchronized static <T> Clone<T> getInstance() {
        if (isNull(instance)) {
            instance = new Clone<T>();
        }
        return instance;
    }

    /**
     * 这是针对同一类的克隆为新对象的方法,其有两个参数,<code>alias</code>和<code>object</code>。
     * 调用者可以根据将对象克隆成新对象。比如项目中有一个信息实体类，客户端程序员编辑信息对象属
     * 性后，并传递到后端接口，后端程序员先根据id从数据库拿到信息的持久类的对象后，并将前端对象
     * 属性值通过{@code getter}方法将值填充到持久类对象的属性中，并保存到数据库中，这就是数据的
     * 克隆。
     * <p>
     * 比如以下代码，克隆出新的对象类：
     * <pre>
     *     <code>
     *            Student student = new Student();
     *            student.setNo("1234354");
     *            student.setName("jack zhu");
     *            student.setDeleted(true);
     *            Course course = new Course();
     *            course.setStudent(student);
     *            course.setName("语文");
     *            Course course1 = Clone.getInstance().resultClone(Course.class, course);
     *            System.out.println(course1);
     *     </code>
     * </pre>
     *
     * @param alias  当前待克隆对象的实体类
     * @param object 待克隆对象
     * @return 克隆后的对象
     * @throws ClassException 如果{@code EntityStorage}对象出现异常，则会抛出异常信息
     */
    public <T> T resultClone(Class<T> alias, T object) throws ClassException {
        return (T) resultClone(getDefaultConstructor(alias), object);
    }

    /**
     * 这是克隆集合对象并以集合对象的顺序存储为新对象的方法。这句话的意思是什么呢？调用者需要把集合类的对象
     * 转存为新对象并保存在容器中时，程序内部会根据原有对象的存储顺序以链表<code>LinkedList</code>的方式保存
     * 在新容器中。其内部调用{@link this#resultClone(Class, List, boolean)}。此时<code>order</code>的值为true。
     * 如下代码所示：
     * <pre>
     *     <code>
     *
     *          public void testTwo(){
     *              List<Course> list=new ArrayList<>();
     *              for (int i = 0;i<10;i++){
     *                  Student student = new Student();
     *                  student.setName("jack zhu");
     *                  student.setNo(String.valueOf(i+1));
     *                  student.setDeleted(true);
     *                  Course course = new Course();
     *                  course.setStudent(student);
     *                  course.setName("语文");
     *                  list.add(course);
     *              }
     *              List<Course> courses = Clone.getInstance().resultOrderClone(Course.class, list);
     *              System.out.println(courses);
     *           }
     *     </code>
     * </pre>
     *
     * @param alias  当前待克隆对象的实体类
     * @param object 待克隆对象
     * @return 克隆后的集合对象
     * @throws ClassException 如果{@code EntityStorage}对象出现异常，则会抛出异常信息
     */
    public <T> List<T> resultOrderClone(Class<T> alias, List<T> objClonings) throws ClassException {
        return resultCloneToList(alias, objClonings, true);
    }

    /**
     * 这是克隆集合对象并不是以集合对象的顺序存储为新对象的方法。这句话的意思是什么呢？调用者需要把集合类的对象
     * 转存为新对象并保存在容器中时，程序内部会根据原有对象的存储顺序以<code>ArrayList</code>的方式保存在新容器
     * 中。其内部调用{@link this#resultClone(Class, List, boolean)}。此时<code>order</code>的值为false。
     * 如下代码所示：
     * <p>
     * <pre>
     *     <code>
     *
     *          public void testTwo(){
     *              List<Course> list=new ArrayList<>();
     *              for (int i = 0;i<10;i++){
     *                  Student student = new Student();
     *                  student.setName("jack zhu");
     *                  student.setNo(String.valueOf(i+1));
     *                  student.setDeleted(true);
     *                  Course course = new Course();
     *                  course.setStudent(student);
     *                  course.setName("语文");
     *                  list.add(course);
     *              }
     *              List<Course> courses = Clone.getInstance().resultClone(Course.class, list);
     *              System.out.println(courses);
     *           }
     *     </code>
     * </pre>
     *
     * @param alias  当前待克隆对象的实体类
     * @param object 待克隆对象
     * @return 克隆后的集合对象
     * @throws ClassException 如果{@code EntityStorage}对象出现异常，则会抛出异常信息
     */
    public <T> List<T> resultCloneToList(Class<T> alias, List<T> objClonings) throws ClassException {
        return resultCloneToList(alias, objClonings, false);
    }

    /**
     * 这是克隆集合对象并存储为新对象的方法。程序会根据调用者出入的<code>order</code>的参数值，来判定新对象
     * 的存储方式，是以链表的方法存储，还是以散列值的方式存储。
     * 如下代码所示：
     * <p>
     * <pre>
     *     <code>
     *
     *          public void testTwo(){
     *              List<Course> list=new ArrayList<>();
     *              for (int i = 0;i<10;i++){
     *                  Student student = new Student();
     *                  student.setName("jack zhu");
     *                  student.setNo(String.valueOf(i+1));
     *                  student.setDeleted(true);
     *                  Course course = new Course();
     *                  course.setStudent(student);
     *                  course.setName("语文");
     *                  list.add(course);
     *              }
     *              List<Course> courses = Clone.getInstance().resultClone(Course.class, list);
     *              System.out.println(courses);
     *           }
     *     </code>
     * </pre>
     *
     * @param alias  当前待克隆对象的实体类
     * @param object 待克隆对象
     * @param order  如果为true，则以链表的方式存储，如果为false，则以散列值的方式存储
     * @return 克隆后的集合对象
     * @throws ClassException 如果{@code EntityStorage}对象出现异常，则会抛出异常信息
     */
    public <T> List<T> resultCloneToList(Class<T> alias, List<T> objects, boolean order) throws ClassException {
        List<T> list = geObjectList(objects, order);
        for (T objCloning : objects) {
            list.add(resultClone(alias, objCloning));
        }
        return list;
    }

    /**
     * 这是针对同一类的克隆对象的方法,其有两个参数,<code>alias</code>和<code>object</code>。调用者
     * 可以根据将对象克隆成新对象。比如项目中有一个岗位实体类，客户端程序员编辑岗位对象属性后，并
     * 传递到后端接口，后端程序员先根据id从数据库拿到岗位的持久类的对象后，并将前端对象属性值通过
     * {@codegetter}方法将值填充到持久类对象的属性中，并保存到数据库中，这就是数据的克隆。
     * <p>
     * 比如以下代码：
     * <pre>
     *     <code>
     *              @Override
     *              public Result updateWorkPosition(Long id, WorkPosition workPosition,) {
     *                  WorkPosition dbworkPosition = workPositionDao.get(id);
     *                  if (null == dbworkPosition) {
     *                      throw new GeneralBizException("不存在编号为" + id + "的工作岗位");
     *                  }
     *                  dbworkPosition.setName(workPosition.getName());
     *                  dbworkPosition.setAddress(workPosition.getAddress());
     *                  dbworkPosition.setWorkExperience(workPosition.getWorkExperience());
     *                  dbworkPosition.setSalaryTreatment(workPosition.getSalaryTreatment());
     *                  dbworkPosition.setNum(workPosition.getNum());
     *                  dbworkPosition.setPublishTime(workPosition.getPublishTime());
     *                  。。。。
     *                  workPositionDao.save(dbworkPosition);
     *                  return ResultUtil.buildSuccess();
     *              }
     *     </code>
     * </pre>
     * 如果我们采用这个方法后，其代码是这样的，代码突然少了很多：
     * <pre>
     *     <code>
     *         @Override
     *          @Override
     *              public Result updateWorkPosition(Long id, WorkPosition workPosition) {
     *                 WorkPosition dbworkPosition = workPositionDao.get(id);
     *                 if (null == dbworkPosition) {
     *                     throw new GeneralBizException("不存在编号为" + id + "的工作岗位");
     *                  }
     *                  WorkPosition dbworkPosition=Clone.getInstance().resultClone(dbworkPosition, workPosition);
     *                  workPositionDao.save(dbworkPosition);
     *                  return ResultUtil.buildSuccess();
     *          }
     *     </code>
     * </pre>
     *
     * @param alias  克隆后的对象
     * @param object 待克隆对象
     * @return 克隆后的对象
     * @throws ClassException 如果{@code EntityStorage}对象出现异常，则会抛出异常信息
     */
    public <T> T resultClone(T objCloned, T objCloning) throws ClassException {
        if (isNull(objCloning)) {
            throw new InformationException("待克隆对象不能为空");
        }
        Class clazz = objCloning.getClass();
        Method[] methods = clazz.getMethods();
        MethodFilters methodFilters = BuilderFilters.builderMethodFilters();
//        set和get、is的存储容器
        Set<EntityStorage> propertyGets = methodFilters.filterByGetter(methods);
        Set<EntityStorage> propertySets = methodFilters.filterBySetter(methods);
//        验证实体存储器
        validStorages(clazz, propertyGets, propertySets);
        try {
            objCloned = isNull(objCloned) ? (T) CommonReflectFactory.getInstance(clazz).getNoArgsConstruct(null).newInstance() : objCloned;
            for (EntityStorage storageGet : propertyGets) {
                String propName = storageGet.getPropertyName();
                Object result = invoke(objCloning, storageGet);
                for (EntityStorage storageSet : propertySets) {
                    if (storageSet.getPropertyName().equals(propName)) {
                        invoke(objCloned, storageSet, result);
                    }
                }
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return objCloned;
    }

    /**
     * 这是根据原有对象生成中间对象的结果。参数<code>var1</code>是数组类型，其存储的在冒号之前的值是待转
     * 对象的属性和其关联类的属性，在冒号之后的值心所转成的新对象的属性，比如<code>alias</code>为
     * {@link com.beantools.testpo.StudentCourse}的对象,而<code>object</code>为{@link com.beantools.testpo.Course}
     * 的对象，其有一属性<code>student</code>，属性类型为<{@link com.beantools.testpo.Student}。也就是说，
     * <code>studentClourse</code>是类<code>Course</code>的别类，存储类<code>Course</code>及其关联类的属性值，
     * 比如下面的代码：
     * <pre>
     *     <code>
     *
     *          public void testFive() {
     *              Student student = new Student();
     *              student.setName("jack zhu");
     *              Course course = new Course();
     *              course.setStudent(student);
     *              course.setName("语文");
     *              String[] str={"student.name:studentName","name:courseName"};
     *              StudentCourse studentCourse = Clone.getInstance().resultClone(str,StudentCourse.class, course);
     *              System.out.println(studentCourse);
     *          }
     *     </code>
     * </pre>
     *
     * @param var1   形参为这种格式的<code>{"student.name:studentName","name:courseName"}</code>数组，
     *               冒号之前的是<code>object</code>的属性，而冒号之后的数据是<code>alias</code>的属性。
     *               这两者可以相同，也可以不相同。
     * @param alias  克隆后的对象
     * @param object 待克隆对象
     * @return 克隆后的对象
     */
    public <T>T resultClone(String[] var1, Class<T> alias, Object object) throws ClassException {
        return (T) resultClone(var1, getDefaultConstructor(alias), object);
    }

    /**
     * 这是克隆对象集合的方法，其内部调用{@link this#resultClone(String[], Class, List, boolean)}方法。具体解析
     * 请参考方法{@link this#resultClone(String[], Class, List, boolean)}的注释
     * <pre>
     *     <code>
     *
     *           public void testSix() {
     *               List<Course> list = new ArrayList<>();
     *               for (int i = 0; i < 5; i++) {
     *                   Student student = new Student();
     *                   student.setName("jack zhu");
     *                   student.setNo(String.valueOf(i + 1));
     *                   Course course = new Course();
     *                   course.setStudent(student);
     *                   course.setName("语文");
     *                   list.add(course);
     *               }
     *               String[] str = {"student.name:studentName", "name:courseName"};
     *               List<StudentCourse> studentCourses = Clone.getInstance().resultOrderClone(str, StudentCourse.class, list);
     *               System.out.println(studentCourses);
     *           }
     *     </code>
     * </pre>
     *
     * @param var1       形参为这种格式的<code>{"student.name:studentName","name:courseName"}</code>数组，
     *                   冒号之前的是<code>object</code>的属性，而冒号之后的数据是<code>alias</code>的属性。
     *                   这两者可以相同，也可以不相同。
     * @param objCloneds 克隆后的对象
     * @param objects    待克隆对象
     * @return 克隆后的对象
     * @throws ClassException 如果{@code EntityStorage}对象出现异常，则会抛出异常信息
     */
    public <T> List resultOrderCloneToList(String[] var1, Class<T> aliasClass, List objects) throws ClassException {
        return resultCloneToList(var1, aliasClass, objects, true);
    }

    /**
     * 这是克隆对象集合的方法，其内部调用{@link this#resultClone(String[], Class, List)}方法。其有一个<order>
     * 属性</order>该属性来判断存储新对象的集合，使用链表<code>LinkedList</code>集合，还是<code>ArrayList</code>
     * 存储。其内部调用{@link this#resultClone(String[], Class, List)}的方法，可以参看其注释帮助理解。
     *
     * @param var1    形参为这种格式的<code>{"student.name:studentName","name:courseName"}</code>数组，
     *                冒号之前的是<code>object</code>的属性，而冒号之后的数据是<code>alias</code>的属性。
     *                这两者可以相同，也可以不相同。
     * @param alias   克隆后的对象
     * @param objects 待克隆对象
     * @return 克隆后的对象
     */
    public <T> List resultCloneToList(String[] var1, Class<T> alias, List objects, boolean order) throws ClassException {
        List list = geObjectList(objects, order);
        for (Object objCloning : objects) {
            list.add(resultClone(var1, getDefaultConstructor(alias), objCloning));
        }
        return list;
    }

    /**
     * 这是根据原有对象生成中间对象的结果。参数<code>var1</code>是数组类型，其存储的在冒号之前的值是待转
     * 对象的属性和其关联类的属性，在冒号之后的值心所转成的新对象的属性，比如<code>alias</code>为
     * {@link com.beantools.testpo.StudentCourse}的对象,而<code>object</code>为{@link com.beantools.testpo.Course}
     * 的对象，其有一属性<code>student</code>，属性类型为<{@link com.beantools.testpo.Student}。也就是说，
     * <code>studentClourse</code>是类<code>Course</code>的别类，存储类<code>Course</code>及其关联类的属性值，
     * 比如下面的代码：
     * <pre>
     *     <code>
     *
     *          public void testSeven() {
     *              Student student = new Student();
     *              student.setName("jack zhu");
     *              Course course = new Course();
     *              course.setStudent(student);
     *              course.setName("语文");
     *              String[] str = {"student.name:studentName"};
     *              StudentCourse studentCourse = new StudentCourse();
     *              studentCourse.setCourseName("数学");
     *              studentCourse = Clone.getInstance().resultClone(str, studentCourse, course);
     *              System.out.println(studentCourse);
     *          }
     *     </code>
     * </pre>
     *
     * @param var1   形参为这种格式的<code>{"student.name:studentName","name:courseName"}</code>数组，
     *               冒号之前的是<code>object</code>的属性，而冒号之后的数据是<code>alias</code>的属性。
     *               这两者可以相同，也可以不相同。
     * @param alias  克隆后的对象
     * @param object 待克隆对象
     * @return 克隆后的对象
     */
    public <T> T resultClone(String[] var1, T alias, Object object) throws ClassException {
        if (ArrayUtil.containNullObject(var1)) {
            var1 = ArrayUtil.removeNull(var1, String.class);
        }
        if (ArrayUtil.isEmpty(var1)) {
            return null;
        }
        Object aliasObj = null;
        for (String s : var1) {
            aliasObj = resultClone(s, alias, object);
        }
        return (T) aliasObj;
    }

    /**
     * 这是克隆新对象的方法。此时的<code>var1</code>的类型是容器类型，也就是说，调用者需要把待转对象的属性和
     * 转出的属性放进容器中，其内部调用{@link this#resultClone(String[], Object, Object)}方法，也就是包容器
     * 转化字符串数组，如以下代码：
     * <pre>
     *     <code>
     *
     *          public void testEight() {
     *              Student student = new Student();
     *              student.setName("jack zhu");
     *              Course course = new Course();
     *              course.setStudent(student);
     *              course.setName("语文");
     *              List list=new ArrayList();
     *              list.add("student.name:studentName");
     *              list.add("name:courseName");
     *              StudentCourse studentCourse = Clone.getInstance().resultClone(list, StudentCourse.class, course);
     *              System.out.println(studentCourse);
     *        }
     *     </code>
     * </pre>
     *
     * @param var1   形参为存储这种格式的"student.name:studengtName"的容器，冒号之前的是<code>object</code>的属性，
     *               而冒号之后的数据是<code>aliasObj</code>的属性。这两者可以相同，也可以不相同
     * @param alias  克隆后的对象
     * @param object 待克隆对象
     * @return 克隆后的对象
     */
    public <T> T resultClone(Collection<String> var1, Class<T> alias, Object object) throws ClassException {
        return (T) resultClone(var1, getDefaultConstructor(alias), object);
    }

    /**
     * 这是克隆新对象的方法。此时的<code>var1</code>的类型是容器类型，也就是说，调用者需要把待转对象的属性和
     * 转出的属性放进容器中，其内部调用{@link this#resultClone(String[], Object, Object)}方法，也就是包容器
     * 转化字符串数组，如以下代码：
     * <pre>
     *     <code>
     *
     *          public void testNine() {
     *              Student student = new Student();
     *              student.setName("jack zhu");
     *              Course course = new Course();
     *              course.setStudent(student);
     *              course.setName("语文");
     *              StudentCourse studentCourse=new StudentCourse();
     *              studentCourse.setCourseName("数学");
     *              List list=new ArrayList();
     *              list.add("student.name:studentName");
     *              studentCourse = Clone.getInstance().resultClone(list, studentCourse, course);
     *              System.out.println(studentCourse);
     *          }
     *     </code>
     * </pre>
     *
     * @param var1   形参为存储这种格式的"student.name:studengtName"的容器，冒号之前的是<code>object</code>的属性，
     *               而冒号之后的数据是<code>aliasObj</code>的属性。这两者可以相同，也可以不相同
     * @param alias  克隆后的对象
     * @param object 待克隆对象
     * @return 克隆后的对象
     */
    public <T> T resultClone(Collection<String> var1, T alias, Object object) throws ClassException {
        if (CollectionUtil.isEmpty(var1)) {
            return null;
        }
        Object aliasObj = null;
        for (String s : var1) {
            aliasObj = resultClone(s, alias, object);
        }
        return (T) aliasObj;
    }

    /**
     * 这是根据原有对象生成中间对象的结果。参数<code>var1</code>是数组类型，其存储的在冒号之前的值是待转
     * 对象的属性和其关联类的属性，在冒号之后的值心所转成的新对象的属性，比如<code>alias</code>为
     * {@link com.beantools.testpo.StudentCourse}的对象,而<code>object</code>为{@link com.beantools.testpo.Course}
     * 的对象，其有一属性<code>student</code>，属性类型为<{@link com.beantools.testpo.Student}。也就是说，
     * <code>studentClourse</code>是类<code>Course</code>的别类，存储类<code>Course</code>及其关联类的属性值，
     * 比如下面的代码：
     * <pre>
     *     <code>
     *
     *          public void testTen() {
     *              Student student = new Student();
     *              student.setName("jack zhu");
     *              Course course = new Course();
     *              course.setStudent(student);
     *              course.setName("语文");
     *              StudentCourse studentCourse = Clone.getInstance().resultClone("name:courseName", StudentCourse.class, course);
     *              System.out.println(studentCourse);
     *          }
     *     </code>
     * </pre>
     *
     * @param var1   形参为这种格式的"student.name:studengtName"字符串，冒号之前的是<code>object
     *               </code>的属性，而冒号之后的数据是<code>aliasObj</code>的属性。这两者可以相同，
     *               也可以不相同
     * @param alias  克隆后的对象
     * @param object 待克隆对象
     * @return 克隆后的对象
     */
    public <T> T resultClone(String var1, Class<T> alias, Object object) throws ClassException {
        return (T) resultClone(var1, getDefaultConstructor(alias), object);
    }

    /**
     * 这是根据原有对象生成中间对象的结果。参数<code>var1</code>是数组类型，其存储的在冒号之前的值是待转
     * 对象的属性和其关联类的属性，在冒号之后的值心所转成的新对象的属性，比如<code>alias</code>为
     * {@link com.beantools.testpo.StudentCourse}的对象,而<code>object</code>为{@link com.beantools.testpo.Course}
     * 的对象，其有一属性<code>student</code>，属性类型为<{@link com.beantools.testpo.Student}。也就是说，
     * <code>studentClourse</code>是类<code>Course</code>的别类，存储类<code>Course</code>及其关联类的属性值，
     * 比如下面的代码：
     * <pre>
     *     <code>
     *
     *          public void testEleven() {
     *              Student student = new Student();
     *              student.setName("jack zhu");
     *              Course course = new Course();
     *              course.setStudent(student);
     *              course.setName("语文");
     *              StudentCourse studentCourse=new StudentCourse();
     *              studentCourse.setCourseName("数学");
     *              studentCourse = Clone.getInstance().resultClone("student.name:studentName", studentCourse, course);
     *              System.out.println(studentCourse);
     *          }
     *     </code>
     * </pre>
     *
     * @param var1   形参为这种格式的"student.name:studengtName"字符串，冒号之前的是<code>object
     *               </code>的属性，而冒号之后的数据是<code>aliasObj</code>的属性。这两者可以相同，
     *               也可以不相同
     * @param alias  克隆后的对象
     * @param object 待克隆对象
     * @return 克隆后的对象
     */
    public <T> T resultClone(String var1, T alias, Object object) throws ClassException {
        if (isBlank(var1)) {
            throw new InformationException("属性字符串不能为空");
        }
        if (isNull(alias) || isNull(object)) {
            return null;
        }
//        原对象的属性
        String var2 = "";
//        别名对象的属性
        String var3 = "";
        if (!var1.contains(SIGN_COLON_OP) && !var1.contains(EN_POINT)) {
            var3 = var2 = var1;
        }
        if (countContains(var1, SIGN_COLON_OP) >= 2) {
            throw new InformationException("var1参数只能包含一个冒号符号");
        }
        if (var1.contains(EN_POINT) && !var1.contains(SIGN_COLON_OP)) {
            throw new InformationException("字符串包含点和英文冒号，必须包含别名");
        }
        if (var1.contains(SIGN_COLON_OP) && var1.contains(EN_POINT) && isBlank(var1.substring(0, var1.lastIndexOf(SIGN_COLON_OP)))) {
            throw new InformationException("字符串存在点和冒号，则冒号之后不能为空");
        }
        if (var1.contains(SIGN_COLON_OP) && isNotBlank(var1.substring(var1.lastIndexOf(SIGN_COLON_OP) + ROUND_DOWN, var1.length()))) {
            var2 = var1.substring(0, var1.lastIndexOf(SIGN_COLON_OP));
            var3 = var1.substring(var1.indexOf(SIGN_COLON_OP) + 1);
        }
        Property property = Property.getInstance();
        Object obj2 = property.getProperty(var2, object);
        return (T) property.setProperty(var3, obj2, alias);
    }

    /**
     * 这里验证某个类是否有set和get方法，因为通过get或is方法拿到被克隆对象的
     * 属性的值，再通过set方法把值塞进对象中
     *
     * @param clazz        对象
     * @param propertyGets get方法实体存储器
     * @param propertySets set方法实体存储器
     * @throws ClassException 抛出类异常信息
     */
    private void validStorages(Class clazz, Set<EntityStorage> propertyGets, Set<EntityStorage> propertySets) throws ClassException {
        if (isEmpty(propertyGets) || containNullObj(propertyGets)) {
            throw new ClassException("没有get或is方法", clazz);
        }
        if (isEmpty(propertySets) || containNullObj(propertyGets)) {
            throw new ClassException("没有set方法", clazz);
        }
    }

    /**
     * 获取默认的构造方法，如果没有默认的构造方法，就会抛出{@code ClassException}
     * 类异常系信息。
     *
     * @param clazz 当前类对象信息
     * @return 返回默认构造器，也就是无参构造器的对象{@code Constructor}
     * @throws ClassException
     */
    private Object getDefaultConstructor(Class clazz) {
        try {
            return CommonReflectFactory.getInstance(clazz).getNoArgsConstruct(null).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 这是通过属性<code>objects</code>来生成多少位数的新的对象容器。如果<code>order = true</code>则生成的容器
     * 是链表形式的有序性，还是散列形式的无序性。
     *
     * @param objects 对象的集合
     * @param order   布尔类型，true表示成的容器是链表形式的有序性，
     *                false表示散列形式的无序性。
     * @return 新生成的容器
     */
    private <T> List geObjectList(List<T> objects, boolean order) {
        Collection<T> coll = objects;
        if (CollectionUtil.containNullObj(objects)) {
            coll = CollectionUtil.removeNullObject(objects);
        }
        if (CollectionUtil.isEmpty(coll)) {
            return null;
        }
        List list = order ? new LinkedList() : new ArrayList(coll.size());
        return list;
    }
}
